package com.example.project.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.example.project.dto.vo.admin.AdminMenuVO;
import com.example.project.dto.vo.admin.AdminPermVO;
import com.example.project.dto.vo.admin.AdminRoleVO;
import com.example.project.entity.*;
import com.example.project.mapper.*;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class AdminRoleService {

    private final RoleMapper roleMapper;
    private final AdminRolePermissionMapper adminRolePermissionMapper;
    private final AdminPermissionMapper adminPermissionMapper;
    private final AdminMenuMapper adminMenuMapper;
    private final AdminRoleMenuMapper adminRoleMenuMapper;
    private final AdminUserRoleMapper adminUserRoleMapper;
    private final UserMapper userMapper;

    public List<AdminRoleVO> list() {
        List<Role> roles = roleMapper.selectList(new LambdaQueryWrapper<>());
        return roles.stream().map(this::enrichRole).collect(Collectors.toList());
    }

    public AdminRoleVO findById(Integer id) {
        Role role = roleMapper.selectById(id);
        if (role == null) return null;
        return enrichRole(role);
    }

    @Transactional
    public void addOrUpdate(AdminRoleVO vo) {
        Role role = new Role();
        role.setName(vo.getName());
        role.setNameZh(vo.getNameZh());
        role.setEnabled(vo.getEnabled());
        if (role.getId() == null) {
            roleMapper.insert(role);
            vo.setId(role.getId());
        } else {
            roleMapper.updateById(role);
        }
        // 同步权限
        savePermChanges(vo.getId(), vo.getPerms());
    }

    public List<AdminRoleVO> listRolesByUser(String username) {
        User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUserName, username));
        if (user == null) return Collections.emptyList();
        List<AdminUserRole> urs = adminUserRoleMapper.selectList(new LambdaQueryWrapper<AdminUserRole>().eq(AdminUserRole::getUid, user.getId().intValue()));
        if (urs.isEmpty()) return Collections.emptyList();
        List<Integer> rids = urs.stream().map(AdminUserRole::getRid).collect(Collectors.toList());
        List<Role> roles = roleMapper.selectBatchIds(rids);
        return roles.stream().map(this::enrichRole).collect(Collectors.toList());
    }

    @Transactional
    public AdminRoleVO updateRoleStatus(Integer rid, boolean enabled) {
        Role inDb = roleMapper.selectById(rid);
        if (inDb == null) return null;
        inDb.setEnabled(enabled);
        roleMapper.updateById(inDb);
        return enrichRole(inDb);
    }

    @Transactional
    public boolean editRole(AdminRoleVO vo) {
        try {
            addOrUpdate(vo);
            return true;
        } catch (IllegalArgumentException e) {
            return false;
        }
    }

    @Transactional
    public void savePermChanges(Integer rid, List<AdminPermVO> perms) {
        // 删除原绑定
        adminRolePermissionMapper.delete(new LambdaQueryWrapper<AdminRolePermission>().eq(AdminRolePermission::getRid, rid));
        if (perms == null || perms.isEmpty()) return;
        for (AdminPermVO p : perms) {
            if (p.getId() == null) continue;
            AdminRolePermission rp = new AdminRolePermission();
            rp.setRid(rid);
            rp.setPid(p.getId());
            adminRolePermissionMapper.insert(rp);
        }
    }

    public List<AdminMenuVO> getMenusByRoleId(Integer rid) {
        List<AdminRoleMenu> list = adminRoleMenuMapper.selectList(new LambdaQueryWrapper<AdminRoleMenu>().eq(AdminRoleMenu::getRid, rid));
        if (list.isEmpty()) return Collections.emptyList();
        List<Integer> mids = list.stream().map(AdminRoleMenu::getMid).collect(Collectors.toList());
        List<AdminMenu> menus = adminMenuMapper.selectBatchIds(mids);
        return menus.stream().map(this::toMenuVO).collect(Collectors.toList());
    }

    /**
     * 为多个角色构建可见菜单的树结构
     */
    public List<AdminMenuVO> getMenuTreeByRoleIds(List<Integer> rids) {
        if (rids == null || rids.isEmpty()) return Collections.emptyList();
        // 如果包含系统管理员，直接返回整棵树
        List<Role> roles = roleMapper.selectBatchIds(rids);
        boolean isSystemAdmin = roles.stream().anyMatch(r -> "systemAdmin".equals(r.getName()));
        if (isSystemAdmin) {
            return listMenuTree();
        }

        // 汇总所有角色可见的菜单ID
        List<AdminRoleMenu> binds = adminRoleMenuMapper.selectList(new LambdaQueryWrapper<AdminRoleMenu>().in(AdminRoleMenu::getRid, rids));
        if (binds.isEmpty()) return Collections.emptyList();
        Set<Integer> allowMenuIds = binds.stream().map(AdminRoleMenu::getMid).collect(Collectors.toSet());

        // 查询这些菜单
        List<AdminMenu> allMenus = adminMenuMapper.selectList(new LambdaQueryWrapper<>());
        Map<Integer, AdminMenu> id2menu = allMenus.stream().collect(Collectors.toMap(AdminMenu::getId, m -> m));

        // 允许的菜单 + 保证它们的父级链路存在（用于展示树）
        Set<Integer> withParents = new HashSet<>(allowMenuIds);
        for (Integer mid : new ArrayList<>(allowMenuIds)) {
            Integer pid = id2menu.get(mid) != null ? id2menu.get(mid).getParentId() : null;
            while (pid != null && pid != 0) {
                if (!withParents.add(pid)) break;
                AdminMenu parent = id2menu.get(pid);
                pid = parent != null ? parent.getParentId() : null;
            }
        }

        List<AdminMenu> scopedMenus = allMenus.stream().filter(m -> withParents.contains(m.getId())).collect(Collectors.toList());
        return buildMenuTree(scopedMenus);
    }

    /**
     * 游客菜单树：若存在 visitor 角色则使用其配置，否则返回空或可选的公共菜单
     */
    public List<AdminMenuVO> getVisitorMenuTree() {
        Role visitor = roleMapper.selectOne(new LambdaQueryWrapper<Role>().eq(Role::getName, "visitor"));
        if (visitor == null) return Collections.emptyList();
        return getMenuTreeByRoleIds(Collections.singletonList(visitor.getId()));
    }

    private List<AdminMenuVO> buildMenuTree(List<AdminMenu> menus) {
        Map<Integer, AdminMenuVO> id2vo = new HashMap<>();
        for (AdminMenu m : menus) {
            AdminMenuVO vo = toMenuVO(m);
            vo.setChildren(new ArrayList<>());
            id2vo.put(vo.getId(), vo);
        }
        List<AdminMenuVO> roots = new ArrayList<>();
        for (AdminMenuVO vo : id2vo.values()) {
            if (vo.getParentId() == null || vo.getParentId() == 0) {
                roots.add(vo);
            } else {
                AdminMenuVO parent = id2vo.get(vo.getParentId());
                if (parent != null) parent.getChildren().add(vo);
            }
        }
        return roots;
    }

    public List<AdminMenuVO> listMenuTree() {
        List<AdminMenu> menus = adminMenuMapper.selectList(new LambdaQueryWrapper<>());
        Map<Integer, AdminMenuVO> id2vo = new HashMap<>();
        for (AdminMenu m : menus) {
            AdminMenuVO vo = toMenuVO(m);
            vo.setChildren(new ArrayList<>());
            id2vo.put(vo.getId(), vo);
        }
        List<AdminMenuVO> roots = new ArrayList<>();
        for (AdminMenuVO vo : id2vo.values()) {
            if (vo.getParentId() == null || vo.getParentId() == 0) {
                roots.add(vo);
            } else {
                AdminMenuVO parent = id2vo.get(vo.getParentId());
                if (parent != null) parent.getChildren().add(vo);
                else roots.add(vo);
            }
        }
        return roots;
    }

    @Transactional
    public void updateRoleMenus(Integer rid, List<Integer> mids) {
        adminRoleMenuMapper.delete(new LambdaQueryWrapper<AdminRoleMenu>().eq(AdminRoleMenu::getRid, rid));
        if (mids == null || mids.isEmpty()) return;
        for (Integer mid : mids) {
            AdminRoleMenu rm = new AdminRoleMenu();
            rm.setRid(rid);
            rm.setMid(mid);
            adminRoleMenuMapper.insert(rm);
        }
    }

    private AdminRoleVO enrichRole(Role role) {
        AdminRoleVO vo = new AdminRoleVO();
        vo.setId(role.getId());
        vo.setName(role.getName());
        vo.setNameZh(role.getNameZh());
        vo.setEnabled(Boolean.TRUE.equals(role.getEnabled()));
        // perms
        List<AdminRolePermission> rps = adminRolePermissionMapper.selectList(new LambdaQueryWrapper<AdminRolePermission>().eq(AdminRolePermission::getRid, role.getId()));
        if (!rps.isEmpty()) {
            List<Integer> pids = rps.stream().map(AdminRolePermission::getPid).collect(Collectors.toList());
            List<AdminPermission> perms = adminPermissionMapper.selectBatchIds(pids);
            List<AdminPermVO> permVos = perms.stream().map(this::toPermVO).collect(Collectors.toList());
            vo.setPerms(permVos);
        } else {
            vo.setPerms(Collections.emptyList());
        }
        // menus (flat for role)
        vo.setMenus(getMenusByRoleId(role.getId()));
        return vo;
    }

    private AdminPermVO toPermVO(AdminPermission p) {
        AdminPermVO vo = new AdminPermVO();
        vo.setId(p.getId());
        vo.setName(p.getName());
        vo.setDesc_(p.getDesc_());
        vo.setUrl(p.getUrl());
        return vo;
    }

    private AdminMenuVO toMenuVO(AdminMenu m) {
        AdminMenuVO vo = new AdminMenuVO();
        vo.setId(m.getId());
        vo.setPath(m.getPath());
        vo.setName(m.getName());
        vo.setNameZh(m.getNameZh());
        vo.setIconCls(m.getIconCls());
        vo.setComponent(m.getComponent());
        vo.setParentId(m.getParentId());
        vo.setChildren(Collections.emptyList());
        return vo;
    }
}


